package java_thinking.unit_12;

/**
 * @Description :异常的限制
 * 当覆盖方法时，只能抛出在基类方法的异常说明里列出的那些异常。这意味着，
 * 当基类使用的代码应用到其派生类对象时，一样能够工作。
 *
 * 1.异常限制对构造器不起作用
 *
 * 　　子类构造器不必理会基类构造器所抛出的异常。然而，因为基类构造器必须以这样或那样的方式被调用（这里默认构造器将自动被调用）
 *     ，派生类构造器的异常说明必须包含基类构造器的异常说明。
 *
 * 2.派生类构造器不能捕获基类构造器抛出的异常
 *
 * 　　因为 super() 必须位于子类构造器的第一行，而若要捕获父类构造器的异常的话，则第一行必须是 try 子句，这样会导致编译不会通过。
 *
 * 3.派生类所重写的方法抛出的异常列表不能大于父类该方法的异常列表，即前者必须是后者的子集
 *
 * 　　通过强制派生类遵守基类方法的异常说明，对象的可替换性得到了保证。需要指出的是，派生类方法可以不抛出任何异常，即使基类中对
 *     应方法具有异常说明。也就是说，一个出现在基类方法的异常说明中的异常，不一定会出现在派生类方法的异常说明里。
 *
 * 4.异常说明不是方法签名的一部分
 *
 * 　　尽管在继承过程中，编译器会对异常说明做强制要求，但异常说明本身并不属于方法类型的一部分，方法类型是由方法的名字及其参数列
 *     表组成。因此，不能基于异常说明来重载方法。
 *
 * 总结：某个特定方法的"异常说明的接口"不是变大了而是变小了，这恰好和类接口在继承时的情形相反
 *
 * 有思维导图
 * @author: cww
 * @DateTime: 2019-03-23 21:40
 */

class BaseballException extends Exception {}
class Foul extends BaseballException {}
class Strike extends BaseballException {}

abstract class Inning {
    public Inning() throws BaseballException {}
    public void event() throws BaseballException {
        // Doesn’t actually have to throw anything
    }
    public abstract void atBat() throws Strike, Foul;
    public void walk() {} // Throws no checked exceptions
    public void walk1() throws PopFoul{} // Throws no checked exceptions
}

class StormException extends Exception {}
class RainedOut extends StormException {}
class PopFoul extends Foul {}

interface Storm {
    public void event() throws RainedOut;
    public void rainHard() throws RainedOut;
}

/**
 * @author asd730520@live.com
 */
public class StormyInning extends Inning implements Storm {
    // OK to add new exceptions for constructors, but you must deal with the base constructor exceptions:

    /**
     * 构造函数可以添加新的异常，但是无论是否添加新的异常，必须加上基类的异常(或该异常的父类)
     * @throws RainedOut
     * @throws BaseballException
     */
    public StormyInning() throws RainedOut ,BaseballException {
        //派生类构造器不能捕获基类构造器抛出的异常,因为super要放在第一行
        super();
    }

    public StormyInning(String s) throws Foul, BaseballException {}

    // Regular methods must conform to base class:

    /**
     * 父类的方法如果没有抛出异常子类不能添加新异常
     * @throws RainedOut
     */
//    public void walk() throws PopFoul {}   //Compile error

    @Override
    public void walk1() throws PopFoul {}   //Compile error

    // Interface CANNOT add exceptions to existing methods from the base class:

    /**
     * 接口的实现无法添加新异常
     * event()两个父类都有，但是两个父类event方法抛出异常不一样，如果子类也要抛出，则两个
     * 父类要抛出同样的异常，子类才能加上
     * @throws RainedOut
     */
//    @Override
//    public void event() throws BaseballException{}

    // You can choose to not throw any exceptions, even if the base version does:

    /**
     * 派生类方法可以不抛出任何异常，即使基类中对应方法具有异常说明
     */
    @Override
    public void event() {}

    // If the method doesn’t already exist in the base class, the exception is OK:

    @Override
    public void rainHard() throws RainedOut {}


    // Overridden methods can throw inherited exceptions:

    /**
     * 继承或实现覆写的方法可以抛出父类中抛出异常的子类异常
     * @throws PopFoul
     */
    @Override
    public void atBat() throws PopFoul {}

    public static void main(String[] args) {
        try {
            StormyInning si = new StormyInning();
            si.atBat();
        } catch(PopFoul e) {
            System.out.println("Pop foul");
        } catch(RainedOut e) {
            System.out.println("Rained out");
        } catch(BaseballException e) {
            System.out.println("Generic baseball exception");
        }

        // Strike not thrown in derived version.
        try {

            // What happens if you upcast? ----“编译器的类型检查是静态的，是针对引用的！！！”
            //如果是向上转型成基类，那编译器就会要求补货基类的异常
            Inning i = new StormyInning();
            i.atBat();
            // You must catch the exceptions from the base-class version of the method:
        } catch(Strike e) {
            System.out.println("Strike");
        } catch(Foul e) {
            System.out.println("Foul");
        } catch(RainedOut e) {
            System.out.println("Rained out");
        } catch(BaseballException e) {
            System.out.println("Generic baseball exception");
        }
    }
}
